#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "platform_data_special.h"
#include "stm32mp157xxx.h"


struct stm32mp157a{
	unsigned int major;
	struct resource *resource[5];
	struct class *cls;
	struct device *dev;
	unsigned int gpio_count;
	unsigned int get_gpio;
	struct Platform_data_spex *spex;
};
struct stm32mp157a *drv_led;
int drv_led_open(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	
	return ret;
}
	
int drv_led_close(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	return ret;
}
ssize_t drv_led_write(struct file *flp, const char __user *buf, size_t size , loff_t *flag)
{
	int ret =0;
	int led_status=0;
	printk("---%s---\r\n",__FUNCTION__);
	ret = copy_from_user(&led_status, buf, size);
	if(ret !=0)
	{
		printk("copy_from_user_err\r\n");
		return ret;
	}
	if(led_status == 0)	
	{
		gpio_set_value(drv_led->get_gpio, 0);
	}
	else
	{
		gpio_set_value(drv_led->get_gpio, 1);
	}
	return ret;
}

const struct file_operations fops={
	.open = drv_led_open,
	.release = drv_led_close,
	.write = drv_led_write,
	
};

int drv_hello_probe(struct platform_device *pdev)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	//实例化一个对象
	drv_led= kzalloc(sizeof(struct stm32mp157a), GFP_KERNEL);
	if(IS_ERR(drv_led))
	{
		printk("kzalloc_err\r\n");
		ret = PTR_ERR(drv_led);
		return ret;
	}
	drv_led->spex = kzalloc(sizeof(struct Platform_data_spex), GFP_KERNEL);
	if(IS_ERR(drv_led->spex))
	{
		printk("spex_kzalloc_err\r\n");
		ret = PTR_ERR(drv_led->spex);
		goto spex_kzalloc_err;
	}
	of_property_read_u32_index(pdev->dev.of_node, "minum", 0, &drv_led->spex->minum);
	of_property_read_string(pdev->dev.of_node, "dev_name", &drv_led->spex->name);
	printk("minum=%d name=%s\r\n",drv_led->spex->minum,drv_led->spex->name);

	//申请设备号
	drv_led->major = register_chrdev(0, drv_led->spex->name, &fops);
	if(drv_led->major < 0)
	{
		printk("register_chrdev_err\r\n");
		goto register_chrdev_err;
	}
	//创建类
	drv_led->cls = class_create(THIS_MODULE, drv_led->spex->name);
	if(IS_ERR(drv_led->cls))
	{
		printk("class_create_err\r\n");
		ret = PTR_ERR(drv_led->cls);
		goto class_create_err;
	}
	//创建节点
	drv_led->dev = device_create(drv_led->cls, NULL, MKDEV(drv_led->major, drv_led->spex->minum), NULL, drv_led->spex->name);
	if(IS_ERR(drv_led->dev))
	{
		printk("device_create_err\r\n");
		ret = PTR_ERR(drv_led->dev);
		goto device_create_err;
	}
	//硬件初始化
	//获取GPIO数量
	drv_led->gpio_count = of_gpio_count(pdev->dev.of_node);
	if(drv_led->gpio_count < 0)
	{
		printk("of_gpio_count_err\r\n");
		ret = drv_led->gpio_count;
		goto of_gpio_count_err;
	}
	//获取gpio标号
	drv_led->get_gpio = of_get_gpio(pdev->dev.of_node, 0);
	//申请权限
	gpio_request(drv_led->get_gpio, "led0");
	
	//设置GPIO的方向
	gpio_direction_output(drv_led->get_gpio,0);

	gpio_set_value(drv_led->get_gpio, 0);
	return ret;	
of_gpio_count_err:
	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));
device_create_err:
	class_destroy(drv_led->cls );
class_create_err:
	unregister_chrdev(drv_led->major,drv_led->spex->name);
register_chrdev_err:
	kfree(drv_led->spex);
spex_kzalloc_err:
	kfree(drv_led);

	return ret;

}
int drv_hello_remove(struct platform_device *pdev)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	gpio_free(drv_led->get_gpio);
	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));
	class_destroy(drv_led->cls );
	unregister_chrdev(drv_led->major,drv_led->spex->name);
	kfree(drv_led->spex);
	kfree(drv_led);
	return ret;
}


const struct of_device_id hello_table[]={
	{ .compatible = "stm32mp157a_led0" },
	{ .compatible = "stm32mp15xxx_led0" },
	{ .compatible = "stm32mp157a_led2" },
};

struct platform_driver drv={
	.probe = drv_hello_probe,
	.remove = drv_hello_remove,
	.driver = {
		.name = "hello",
		.of_match_table = hello_table,
	},
};

static int __init drv_hello_init(void)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	platform_driver_register(&drv);
	return ret;
}
void __exit drv_hello_exit(void)
{
	printk("---%s---\r\n",__FUNCTION__);
	platform_driver_unregister(&drv);
}

module_init(drv_hello_init);
module_exit(drv_hello_exit);
MODULE_LICENSE("GPL");

